<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="使用 Terraform 容器">
<meta name="twitter:description" content="<p>不安装Terraform，而是直接运行Terraform容器：调试容器启动参数的过程；创建Docker容器示例；设置terraform别名，如同直接执行本地的命令</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/terraform-run-in-docker.html"/>
<meta property="og:title" content="来玩魔王的咚 | 使用 Terraform 容器" />
<meta property="og:description" content="<p>不安装Terraform，而是直接运行Terraform容器：调试容器启动参数的过程；创建Docker容器示例；设置terraform别名，如同直接执行本地的命令</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>不安装Terraform，而是直接运行Terraform容器：调试容器启动参数的过程；创建Docker容器示例；设置terraform别名，如同直接执行本地的命令</p>" />

    <meta name="tags" content="terraform" />
    <meta name="tags" content="docker" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li class="active"><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2021-04-30 23:00:00+08:00">
                <script>document.write(moment('2021-04-30 23:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2021-04-30 23:00:00+08:00">
                <script>document.write(moment('2021-05-01 13:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            使用 Terraform 容器
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#terraform-jing-xiang">Terraform 镜像</a><ul>
<li><a href="#yun-xing-rong-qi">运行容器</a></li>
<li><a href="#jin-ru-rong-qi-nei-bu">进入容器内部</a></li>
</ul>
</li>
<li><a href="#tiao-shi-rong-qi-qi-dong-ming-ling">调试容器启动命令</a><ul>
<li><a href="#gua-zai-dang-qian-mu-lu">挂载当前目录</a></li>
<li><a href="#tian-jia-pei-zhi-wen-jian">添加配置文件</a></li>
<li><a href="#she-zhi-bie-ming">设置别名</a></li>
</ul>
</li>
<li><a href="#chuang-jian-docker-rong-qi-shi-li">创建Docker容器示例</a><ul>
<li><a href="#chuang-jian-maintf-wen-jian">创建main.tf文件</a></li>
<li><a href="#xiu-gai-rong-qi-qi-dong-can-shu">修改容器启动参数</a></li>
<li><a href="#ce-shi-nginx-rong-qi-shi-li">测试NGINX容器示例</a></li>
<li><a href="#xiao-hui-ce-shi-zi-yuan">销毁测试资源</a></li>
</ul>
</li>
<li><a href="#rong-qi-qi-dong-can-shu-he-bie-ming-she-zhi">容器启动参数和别名设置</a></li>
</ul>
</div>
<h3 id="terraform-jing-xiang"><a class="toclink" href="#terraform-jing-xiang">Terraform 镜像</a></h3>
<p>docker hub 镜像: <a href="https://hub.docker.com/r/hashicorp/terraform">https://hub.docker.com/r/hashicorp/terraform</a>  </p>
<p>下载镜像：</p>
<div class="highlight"><pre><span></span><code>docker pull hashicorp/terraform
</code></pre></div>

<h4 id="yun-xing-rong-qi"><a class="toclink" href="#yun-xing-rong-qi">运行容器</a></h4>
<p>官方的启动命令，并不能这么用：</p>
<div class="highlight"><pre><span></span><code>docker run -i -t hashicorp/terraform:full &lt;command&gt;
docker run -i -t hashicorp/terraform:light plan main.tf
</code></pre></div>

<p>问题：</p>
<ol>
<li>这里的<code>-it</code>似乎没必要</li>
<li>文件<code>main.tf</code>是指向容器内部的，并且容器内也没有这个文件</li>
<li>terraform命令并不支持指定文件名，只能指定目录</li>
</ol>
<p>查看版本信息：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>docker run --rm hashicorp/terraform --version
<span class="go">Terraform v0.15.1</span>
<span class="go">on linux_amd64</span>
</code></pre></div>

<h4 id="jin-ru-rong-qi-nei-bu"><a class="toclink" href="#jin-ru-rong-qi-nei-bu">进入容器内部</a></h4>
<p>用下面的容器可以进入容器内部：</p>
<div class="highlight"><pre><span></span><code>docker run --rm -it --entrypoint<span class="o">=</span><span class="s1">&#39;/bin/sh&#39;</span> hashicorp/terraform
</code></pre></div>

<p>需要替换掉启动命令：<code>--entrypoint='/bin/sh'</code>。<br>
之后就在这个基础上调试容器的启动命令，添加各种参数以满足需要。  </p>
<h3 id="tiao-shi-rong-qi-qi-dong-ming-ling"><a class="toclink" href="#tiao-shi-rong-qi-qi-dong-ming-ling">调试容器启动命令</a></h3>
<p>这里不对对容器做任何修改，而是通过设置启动参数来满足需求。  </p>
<h4 id="gua-zai-dang-qian-mu-lu"><a class="toclink" href="#gua-zai-dang-qian-mu-lu">挂载当前目录</a></h4>
<p>启动容器前，先切换到项目目录，然后把当前目录挂载到容器里。<br>
容器默认的工作目录是根目录，还要切换工作目录。<br>
挂载当前目录：<code>-v $PWD:/workspace/$(basename $PWD)</code><br>
切换工作目录：<code>--workdir /workspace/$(basename $PWD)</code><br>
进到容器内部验证挂载和工作目录：</p>
<div class="highlight"><pre><span></span><code>docker run --rm -it --entrypoint<span class="o">=</span><span class="s1">&#39;/bin/sh&#39;</span> <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<h4 id="tian-jia-pei-zhi-wen-jian"><a class="toclink" href="#tian-jia-pei-zhi-wen-jian">添加配置文件</a></h4>
<p>terraform在linux平台下的配置文件，默认是<code>.terraformrc</code>。  </p>
<div class="highlight"><pre><span></span><code>docker run --rm -it --entrypoint<span class="o">=</span><span class="s1">&#39;/bin/sh&#39;</span> <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    -v ~/.terraformrc:/root/.terraformrc:ro <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p>配置文件只读，不需要在容器内修改。  </p>
<p>配置文件内容如下，添加缓存的设置：</p>
<div class="highlight"><pre><span></span><code>plugin_cache_dir = &quot;$HOME/.terraform.d/plugin-cache&quot;
</code></pre></div>

<p>需要先在本地创建并编辑好内容，容器启动后就挂载到容器内。<br>
这个是完全按照官网的建议来设置的
<a href="https://www.terraform.io/docs/cli/config/config-file.html#provider-plugin-cache">https://www.terraform.io/docs/cli/config/config-file.html#provider-plugin-cache</a>。  </p>
<p>缓存目录也需要挂载，这样在容器销毁时，缓存还能留着以后用。初步可以这样来挂载，后面会改进：</p>
<div class="highlight"><pre><span></span><code>docker run --rm -it --entrypoint<span class="o">=</span><span class="s1">&#39;/bin/sh&#39;</span> <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    -v ~/.terraformrc:/root/.terraformrc:ro <span class="se">\</span>
    -v ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p>这里有个问题，如果要挂载的本地目录不存在，会自动创建。多个层级的目录会自动递归创建。并且创建目录的属主和属组都是root，是容器内部的用户，退出容器后还无法直接用当前用户把这个目录删除。  </p>
<p>改进，仅在文件或目录存在的时候才挂载：  </p>
<div class="highlight"><pre><span></span><code>docker run --rm -it --entrypoint<span class="o">=</span><span class="s1">&#39;/bin/sh&#39;</span> <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r ~/.terraformrc <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> --volume ~/.terraformrc:/root/.terraformrc:ro<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -d ~/.terraform.d/plugin-cache <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache<span class="k">)</span> <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p><em>这里echo语句尽量就不用引号了，会少一些麻烦。echo后面的参数是docker的参数，这里特地用了长参数，不会被echo认作自己的参数。不过echo也没有-v，所以本来也不会有问题。</em>  </p>
<h4 id="she-zhi-bie-ming"><a class="toclink" href="#she-zhi-bie-ming">设置别名</a></h4>
<p>加了上面那些参数后，容器已经可以用了。但是命令太长也不方便。<br>
现在的docker运行的命令如下，去掉了对启动命令的替换：</p>
<div class="highlight"><pre><span></span><code>docker run --rm -it <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r ~/.terraformrc <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> --volume ~/.terraformrc:/root/.terraformrc:ro<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -d ~/.terraform.d/plugin-cache <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache<span class="k">)</span> <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p>参数-it需要留着，有时候命令需要交互，输入yes确认。<br>
<em>之后可能还需要在加别的，比如这里没有本地镜像仓库。也就按照上面的做法再挂载一个目录。</em>  </p>
<p>将上面的命令写到别名中，方便调用：</p>
<div class="highlight"><pre><span></span><code>cat &gt;&gt; ~/.bash_aliases <span class="s">&lt;&lt; EOF</span>
<span class="s">alias terraform=&#39;echo This is run in docker hashicorp/terraform.;\\</span>
<span class="s">    docker container run --rm -it \\</span>
<span class="s">        -v \$PWD:/workspace/\$(basename \$PWD) \\</span>
<span class="s">        --workdir /workspace/\$(basename \$PWD) \\</span>
<span class="s">        \$([ -r ~/.terraformrc ] &amp;&amp; echo --volume ~/.terraformrc:/root/.terraformrc:ro) \\</span>
<span class="s">        \$([ -d ~/.terraform.d/plugin-cache ] &amp;&amp; \\</span>
<span class="s">            echo --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache) \\</span>
<span class="s">        hashicorp/terraform&#39;</span>
<span class="s">EOF</span>
</code></pre></div>

<p><em>这个还不是最终版本</em>  </p>
<h3 id="chuang-jian-docker-rong-qi-shi-li"><a class="toclink" href="#chuang-jian-docker-rong-qi-shi-li">创建Docker容器示例</a></h3>
<p>通过示例来测试容器的使用。<br>
参考官网的入门教程，创建NGINX的Docker容器：<br>
<a href="https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/azure-get-started#quick-start-tutorial">https://learn.hashicorp.com/tutorials/terraform/install-cli?in=terraform/azure-get-started#quick-start-tutorial</a>  </p>
<h4 id="chuang-jian-maintf-wen-jian"><a class="toclink" href="#chuang-jian-maintf-wen-jian">创建main.tf文件</a></h4>
<p>示例里有Linux版本和Windows版本的代码，这里要用Linux的版本。下面是我对两个版本差别的理解：</p>
<p><strong>terraform.required_providers</strong>:<br>
现在都应该用"kreuzwerker/docker"，如果用了"terraform-providers/docker"也会出现Warning，让你更新代码使用"kreuzwerker/docker"。  </p>
<p><strong>provider</strong>:<br>
Windows的host设置用不了，需要一些设置，并且我也没搞出来。直接按Linux版本那样设置为空就好。<br>
容器是运行在WSL2子系统里的，应该算是Linux而不是Windows。这里设置为空，空就是默认设置，默认设置如下：</p>
<div class="highlight"><pre><span></span><code><span class="kr">provider</span><span class="w"> </span><span class="nv">&quot;docker&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">host</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;unix:///var/run/docker.sock&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p><strong>注意</strong>：这个sock文件是在WSL2子系统里的，并不在容器中，需要挂载进去，只读属性。  </p>
<p>下面就是示例中要使用的main.tf文件：</p>
<div class="highlight"><pre><span></span><code><span class="nb">terraform</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="nb">required_providers</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nb">docker</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">      </span><span class="na">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;kreuzwerker/docker&quot;</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kr">provider</span><span class="w"> </span><span class="nv">&quot;docker&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">host</span><span class="w">    </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;unix:///var/run/docker.sock&quot;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;docker_image&quot;</span><span class="w"> </span><span class="nv">&quot;nginx&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="na">name</span><span class="w">         </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;nginx:latest&quot;</span><span class="w"></span>
<span class="w">  </span><span class="na">keep_locally</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="no">false</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kr">resource</span><span class="w"> </span><span class="nc">&quot;docker_container&quot;</span><span class="w"> </span><span class="nv">&quot;nginx&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">  </span><span class="na">image</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">docker_image.nginx.latest</span><span class="w"></span>
<span class="w">  </span><span class="na">name</span><span class="w">  </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;tutorial&quot;</span><span class="w"></span>
<span class="w">  </span><span class="nb">ports</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="na">internal</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">80</span><span class="w"></span>
<span class="w">    </span><span class="na">external</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">8000</span><span class="w"></span>
<span class="w">  </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="xiu-gai-rong-qi-qi-dong-can-shu"><a class="toclink" href="#xiu-gai-rong-qi-qi-dong-can-shu">修改容器启动参数</a></h4>
<p>加上sock文件的只读挂载：</p>
<div class="highlight"><pre><span></span><code>docker run --rm -it <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r ~/.terraformrc <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> --volume ~/.terraformrc:/root/.terraformrc:ro<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -d ~/.terraform.d/plugin-cache <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r /var/run/docker.sock <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume /var/run/docker.sock:/var/run/docker.sock:ro<span class="k">)</span> <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p><em>可以先这么用着，别名最后还能再改改。</em>  </p>
<p>对应的别名设置如下：</p>
<div class="highlight"><pre><span></span><code>cat &gt;&gt; ~/.bash_aliases <span class="s">&lt;&lt; EOF</span>
<span class="s">alias terraform=&#39;echo This is run in docker hashicorp/terraform.;\\</span>
<span class="s">    docker container run --rm -it \\</span>
<span class="s">        -v \$PWD:/workspace/\$(basename \$PWD) \\</span>
<span class="s">        --workdir /workspace/\$(basename \$PWD) \\</span>
<span class="s">        \$([ -r ~/.terraformrc ] &amp;&amp; echo --volume ~/.terraformrc:/root/.terraformrc:ro) \\</span>
<span class="s">        \$([ -d ~/.terraform.d/plugin-cache ] &amp;&amp; \\</span>
<span class="s">            echo --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache) \\</span>
<span class="s">        \$([ -r /var/run/docker.sock ] &amp;&amp; \\</span>
<span class="s">            echo --volume /var/run/docker.sock:/var/run/docker.sock:ro) \\</span>
<span class="s">        hashicorp/terraform&#39;</span>
<span class="s">EOF</span>
</code></pre></div>

<h4 id="ce-shi-nginx-rong-qi-shi-li"><a class="toclink" href="#ce-shi-nginx-rong-qi-shi-li">测试NGINX容器示例</a></h4>
<p><strong>初始化</strong>：  </p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform init
<span class="go">This is run in docker hashicorp/terraform.</span>

<span class="go">Initializing the backend...</span>

<span class="go">Initializing provider plugins...</span>
<span class="go">- Reusing previous version of kreuzwerker/docker from the dependency lock file</span>
<span class="go">- Using previously-installed kreuzwerker/docker v2.11.0</span>

<span class="go">Terraform has been successfully initialized!</span>

<span class="go">You may now begin working with Terraform. Try running &quot;terraform plan&quot; to see</span>
<span class="go">any changes that are required for your infrastructure. All Terraform commands</span>
<span class="go">should now work.</span>

<span class="go">If you ever set or change modules or backend configuration for Terraform,</span>
<span class="go">rerun this command to reinitialize your working directory. If you forget, other</span>
<span class="go">commands will detect it and remind you to do so if necessary.</span>
<span class="gp">$</span>
</code></pre></div>

<p><strong>创建镜像</strong>：  </p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform apply
<span class="go">This is run in docker hashicorp/terraform.</span>

<span class="go">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following</span>
<span class="go">symbols:</span>
<span class="go">  + create</span>

<span class="go">Terraform will perform the following actions:</span>

<span class="gp">  # </span>docker_container.nginx will be created
<span class="go">  + resource &quot;docker_container&quot; &quot;nginx&quot; {</span>
<span class="go">      + attach           = false</span>
<span class="go">      + bridge           = (known after apply)</span>
<span class="go">      + command          = (known after apply)</span>
<span class="go">      + container_logs   = (known after apply)</span>
<span class="go">      + entrypoint       = (known after apply)</span>
<span class="go">      + env              = (known after apply)</span>
<span class="go">      + exit_code        = (known after apply)</span>
<span class="go">      + gateway          = (known after apply)</span>
<span class="go">      + hostname         = (known after apply)</span>
<span class="go">      + id               = (known after apply)</span>
<span class="go">      + image            = (known after apply)</span>
<span class="go">      + init             = (known after apply)</span>
<span class="go">      + ip_address       = (known after apply)</span>
<span class="go">      + ip_prefix_length = (known after apply)</span>
<span class="go">      + ipc_mode         = (known after apply)</span>
<span class="go">      + log_driver       = &quot;json-file&quot;</span>
<span class="go">      + logs             = false</span>
<span class="go">      + must_run         = true</span>
<span class="go">      + name             = &quot;tutorial&quot;</span>
<span class="go">      + network_data     = (known after apply)</span>
<span class="go">      + read_only        = false</span>
<span class="go">      + remove_volumes   = true</span>
<span class="go">      + restart          = &quot;no&quot;</span>
<span class="go">      + rm               = false</span>
<span class="go">      + security_opts    = (known after apply)</span>
<span class="go">      + shm_size         = (known after apply)</span>
<span class="go">      + start            = true</span>
<span class="go">      + stdin_open       = false</span>
<span class="go">      + tty              = false</span>

<span class="go">      + healthcheck {</span>
<span class="go">          + interval     = (known after apply)</span>
<span class="go">          + retries      = (known after apply)</span>
<span class="go">          + start_period = (known after apply)</span>
<span class="go">          + test         = (known after apply)</span>
<span class="go">          + timeout      = (known after apply)</span>
<span class="go">        }</span>

<span class="go">      + labels {</span>
<span class="go">          + label = (known after apply)</span>
<span class="go">          + value = (known after apply)</span>
<span class="go">        }</span>

<span class="go">      + ports {</span>
<span class="go">          + external = 8000</span>
<span class="go">          + internal = 80</span>
<span class="go">          + ip       = &quot;0.0.0.0&quot;</span>
<span class="go">          + protocol = &quot;tcp&quot;</span>
<span class="go">        }</span>
<span class="go">    }</span>

<span class="gp">  # </span>docker_image.nginx will be created
<span class="go">  + resource &quot;docker_image&quot; &quot;nginx&quot; {</span>
<span class="go">      + id           = (known after apply)</span>
<span class="go">      + keep_locally = false</span>
<span class="go">      + latest       = (known after apply)</span>
<span class="go">      + name         = &quot;nginx:latest&quot;</span>
<span class="go">      + output       = (known after apply)</span>
<span class="go">    }</span>

<span class="go">Plan: 2 to add, 0 to change, 0 to destroy.</span>

<span class="go">Do you want to perform these actions?</span>
<span class="go">  Terraform will perform the actions described above.</span>
<span class="go">  Only &#39;yes&#39; will be accepted to approve.</span>

<span class="go">  Enter a value: yes</span>

<span class="go">docker_image.nginx: Creating...</span>
<span class="go">docker_image.nginx: Still creating... [10s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [20s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [30s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [40s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [50s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [1m0s elapsed]</span>
<span class="go">docker_image.nginx: Still creating... [1m10s elapsed]</span>
<span class="go">docker_image.nginx: Creation complete after 1m14s [id=sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5bnginx:latest]</span>
<span class="go">docker_container.nginx: Creating...</span>
<span class="go">docker_container.nginx: Creation complete after 1s [id=cfce68f795a546e81b4e420a51cb1d288b1faf952e181da4a24c261d2eb629ad]</span>

<span class="go">Apply complete! Resources: 2 added, 0 changed, 0 destroyed.</span>
<span class="gp">$ </span>
</code></pre></div>

<p><strong>验证</strong><br>
可以直接用浏览器打开，或者使用curl命令：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>curl localhost:8000
<span class="go">&lt;!DOCTYPE html&gt;</span>
<span class="go">&lt;html&gt;</span>
<span class="go">&lt;head&gt;</span>
<span class="go">&lt;title&gt;Welcome to nginx!&lt;/title&gt;</span>
<span class="go">&lt;style&gt;</span>
<span class="go">    body {</span>
<span class="go">        width: 35em;</span>
<span class="go">        margin: 0 auto;</span>
<span class="go">        font-family: Tahoma, Verdana, Arial, sans-serif;</span>
<span class="go">    }</span>
<span class="go">&lt;/style&gt;</span>
<span class="go">&lt;/head&gt;</span>
<span class="go">&lt;body&gt;</span>
<span class="go">&lt;h1&gt;Welcome to nginx!&lt;/h1&gt;</span>
<span class="go">&lt;p&gt;If you see this page, the nginx web server is successfully installed and</span>
<span class="go">working. Further configuration is required.&lt;/p&gt;</span>

<span class="go">&lt;p&gt;For online documentation and support please refer to</span>
<span class="go">&lt;a href=&quot;http://nginx.org/&quot;&gt;nginx.org&lt;/a&gt;.&lt;br/&gt;</span>
<span class="go">Commercial support is available at</span>
<span class="go">&lt;a href=&quot;http://nginx.com/&quot;&gt;nginx.com&lt;/a&gt;.&lt;/p&gt;</span>

<span class="go">&lt;p&gt;&lt;em&gt;Thank you for using nginx.&lt;/em&gt;&lt;/p&gt;</span>
<span class="go">&lt;/body&gt;</span>
<span class="go">&lt;/html&gt;</span>
<span class="gp">$ </span>
</code></pre></div>

<h4 id="xiao-hui-ce-shi-zi-yuan"><a class="toclink" href="#xiao-hui-ce-shi-zi-yuan">销毁测试资源</a></h4>
<p>执行命令后会销毁资源，包括容器和镜像，总之很干净：</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>terraform destroy
<span class="go">This is run in docker hashicorp/terraform.</span>
<span class="go">docker_image.nginx: Refreshing state... [id=sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5bnginx:latest]</span>
<span class="go">docker_container.nginx: Refreshing state... [id=cfce68f795a546e81b4e420a51cb1d288b1faf952e181da4a24c261d2eb629ad]</span>

<span class="go">Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following</span>
<span class="go">symbols:</span>
<span class="go">  - destroy</span>

<span class="go">Terraform will perform the following actions:</span>

<span class="gp">  # </span>docker_container.nginx will be destroyed
<span class="go">  - resource &quot;docker_container&quot; &quot;nginx&quot; {</span>
<span class="go">      - attach            = false -&gt; null</span>
<span class="go">      - command           = [</span>
<span class="go">          - &quot;nginx&quot;,</span>
<span class="go">          - &quot;-g&quot;,</span>
<span class="go">          - &quot;daemon off;&quot;,</span>
<span class="go">        ] -&gt; null</span>
<span class="go">      - cpu_shares        = 0 -&gt; null</span>
<span class="go">      - dns               = [] -&gt; null</span>
<span class="go">      - dns_opts          = [] -&gt; null</span>
<span class="go">      - dns_search        = [] -&gt; null</span>
<span class="go">      - entrypoint        = [</span>
<span class="go">          - &quot;/docker-entrypoint.sh&quot;,</span>
<span class="go">        ] -&gt; null</span>
<span class="go">      - env               = [] -&gt; null</span>
<span class="go">      - gateway           = &quot;172.17.0.1&quot; -&gt; null</span>
<span class="go">      - group_add         = [] -&gt; null</span>
<span class="go">      - hostname          = &quot;cfce68f795a5&quot; -&gt; null</span>
<span class="go">      - id                = &quot;cfce68f795a546e81b4e420a51cb1d288b1faf952e181da4a24c261d2eb629ad&quot; -&gt; null</span>
<span class="go">      - image             = &quot;sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5b&quot; -&gt; null</span>
<span class="go">      - init              = false -&gt; null</span>
<span class="go">      - ip_address        = &quot;172.17.0.5&quot; -&gt; null</span>
<span class="go">      - ip_prefix_length  = 16 -&gt; null</span>
<span class="go">      - ipc_mode          = &quot;private&quot; -&gt; null</span>
<span class="go">      - links             = [] -&gt; null</span>
<span class="go">      - log_driver        = &quot;json-file&quot; -&gt; null</span>
<span class="go">      - log_opts          = {} -&gt; null</span>
<span class="go">      - logs              = false -&gt; null</span>
<span class="go">      - max_retry_count   = 0 -&gt; null</span>
<span class="go">      - memory            = 0 -&gt; null</span>
<span class="go">      - memory_swap       = 0 -&gt; null</span>
<span class="go">      - must_run          = true -&gt; null</span>
<span class="go">      - name              = &quot;tutorial&quot; -&gt; null</span>
<span class="go">      - network_data      = [</span>
<span class="go">          - {</span>
<span class="go">              - gateway                   = &quot;172.17.0.1&quot;</span>
<span class="go">              - global_ipv6_address       = &quot;&quot;</span>
<span class="go">              - global_ipv6_prefix_length = 0</span>
<span class="go">              - ip_address                = &quot;172.17.0.5&quot;</span>
<span class="go">              - ip_prefix_length          = 16</span>
<span class="go">              - ipv6_gateway              = &quot;&quot;</span>
<span class="go">              - network_name              = &quot;bridge&quot;</span>
<span class="go">            },</span>
<span class="go">        ] -&gt; null</span>
<span class="go">      - network_mode      = &quot;default&quot; -&gt; null</span>
<span class="go">      - privileged        = false -&gt; null</span>
<span class="go">      - publish_all_ports = false -&gt; null</span>
<span class="go">      - read_only         = false -&gt; null</span>
<span class="go">      - remove_volumes    = true -&gt; null</span>
<span class="go">      - restart           = &quot;no&quot; -&gt; null</span>
<span class="go">      - rm                = false -&gt; null</span>
<span class="go">      - security_opts     = [] -&gt; null</span>
<span class="go">      - shm_size          = 64 -&gt; null</span>
<span class="go">      - start             = true -&gt; null</span>
<span class="go">      - stdin_open        = false -&gt; null</span>
<span class="go">      - sysctls           = {} -&gt; null</span>
<span class="go">      - tmpfs             = {} -&gt; null</span>
<span class="go">      - tty               = false -&gt; null</span>

<span class="go">      - ports {</span>
<span class="go">          - external = 8000 -&gt; null</span>
<span class="go">          - internal = 80 -&gt; null</span>
<span class="go">          - ip       = &quot;0.0.0.0&quot; -&gt; null</span>
<span class="go">          - protocol = &quot;tcp&quot; -&gt; null</span>
<span class="go">        }</span>
<span class="go">    }</span>

<span class="gp">  # </span>docker_image.nginx will be destroyed
<span class="go">  - resource &quot;docker_image&quot; &quot;nginx&quot; {</span>
<span class="go">      - id           = &quot;sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5bnginx:latest&quot; -&gt; null</span>
<span class="go">      - keep_locally = false -&gt; null</span>
<span class="go">      - latest       = &quot;sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5b&quot; -&gt; null</span>
<span class="go">      - name         = &quot;nginx:latest&quot; -&gt; null</span>
<span class="go">    }</span>

<span class="go">Plan: 0 to add, 0 to change, 2 to destroy.</span>

<span class="go">Do you really want to destroy all resources?</span>
<span class="go">  Terraform will destroy all your managed infrastructure, as shown above.</span>
<span class="go">  There is no undo. Only &#39;yes&#39; will be accepted to confirm.</span>

<span class="go">  Enter a value: yes</span>

<span class="go">docker_container.nginx: Destroying... [id=cfce68f795a546e81b4e420a51cb1d288b1faf952e181da4a24c261d2eb629ad]</span>
<span class="go">docker_container.nginx: Destruction complete after 1s</span>
<span class="go">docker_image.nginx: Destroying... [id=sha256:62d49f9bab67f7c70ac3395855bf01389eb3175b374e621f6f191bf31b54cd5bnginx:latest]</span>
<span class="go">docker_image.nginx: Destruction complete after 0s</span>

<span class="go">Destroy complete! Resources: 2 destroyed.</span>
<span class="gp">$</span>
</code></pre></div>

<h3 id="rong-qi-qi-dong-can-shu-he-bie-ming-she-zhi"><a class="toclink" href="#rong-qi-qi-dong-can-shu-he-bie-ming-she-zhi">容器启动参数和别名设置</a></h3>
<p>这个放上最终版，之后可能还会来继续改进。<br>
启动参数说明：</p>
<ul>
<li><code>--rm</code>: 运行结束后销毁容器</li>
<li><code>-it</code>: 提供终端，进行交换式访问。命令中需要yes确认</li>
<li>挂载当前目录到容器的/workspace目录下</li>
<li>启动容器后切换当前工作目录</li>
<li>只读挂载terraform配置文件，<code>~/.terraformrc</code></li>
<li>挂载terraform缓存目录，<code>~/.terraform.d/plugin-cache</code></li>
<li>只读挂载terraform本地镜像仓库，<code>~/.terraform.d/plugins</code></li>
<li>只读挂载docker的sock文件，<code>/var/run/docker.sock</code></li>
</ul>
<p>完整的启动参数</p>
<div class="highlight"><pre><span></span><code>docker container run --rm -it <span class="se">\</span>
    -v <span class="nv">$PWD</span>:/workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    --workdir /workspace/<span class="k">$(</span>basename <span class="nv">$PWD</span><span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r ~/.terraformrc <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="nb">echo</span> --volume ~/.terraformrc:/root/.terraformrc:ro<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -d ~/.terraform.d/plugin-cache <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -d ~/.terraform.d/plugins <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume ~/.terraform.d/plugins:/root/.terraform.d/plugins:ro<span class="k">)</span> <span class="se">\</span>
    <span class="k">$(</span><span class="o">[</span> -r /var/run/docker.sock <span class="o">]</span> <span class="o">&amp;&amp;</span> <span class="se">\</span>
        <span class="nb">echo</span> --volume /var/run/docker.sock:/var/run/docker.sock:ro<span class="k">)</span> <span class="se">\</span>
    hashicorp/terraform
</code></pre></div>

<p>添加别名：</p>
<div class="highlight"><pre><span></span><code>cat &gt;&gt; ~/.bash_aliases <span class="s">&lt;&lt; EOF</span>
<span class="s">alias terraform=&#39;echo This is run in docker hashicorp/terraform.;\\</span>
<span class="s">    docker container run --rm -it \\</span>
<span class="s">        -v \$PWD:/workspace/\$(basename \$PWD) \\</span>
<span class="s">        --workdir /workspace/\$(basename \$PWD) \\</span>
<span class="s">        \$([ -r ~/.terraformrc ] &amp;&amp; echo --volume ~/.terraformrc:/root/.terraformrc:ro) \\</span>
<span class="s">        \$([ -d ~/.terraform.d/plugin-cache ] &amp;&amp; \\</span>
<span class="s">            echo --volume ~/.terraform.d/plugin-cache:/root/.terraform.d/plugin-cache) \\</span>
<span class="s">        \$([ -d ~/.terraform.d/plugins ] &amp;&amp; \\</span>
<span class="s">            echo --volume ~/.terraform.d/plugins:/root/.terraform.d/plugins) \\</span>
<span class="s">        \$([ -r /var/run/docker.sock ] &amp;&amp; \\</span>
<span class="s">            echo --volume /var/run/docker.sock:/var/run/docker.sock:ro) \\</span>
<span class="s">        hashicorp/terraform&#39;</span>
<span class="s">EOF</span>
</code></pre></div>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>